package com.googlecode.vanaraha.adapter.simian
import com.googlecode.vanaraha.tool._
import com.googlecode.vanaraha.utils.Utils._
import com.googlecode.vanaraha.utils.PreferenceStore
import scala.collection.mutable
import com.googlecode.vanaraha.utils.Utils.logger._
import com.googlecode.vanaraha.data._
import au.com.redhillconsulting.simian.{Option, Options, Checker,
                                         CheckSummary, Block, AuditListener, FileLoader, 
                                         StreamLoader, SourceFile => SimianSourceFile}
  
   

class SimianDuplicateTool extends DuplicateFinderTrait{
	
	override def name = "Simian"
	override def run(store: PreferenceStore, files: Array[String], feedBack: ProgressFeedBack)
				: (DuplicateCheckSummary, Array[DuplicateSet]) = {
	  import SimianDuplicateTool.{createOptions, findDuplicates}			  
	 
	  feedBack updateMsg("Initializing SimianDuplicateTool")	  
	  val simianOptions = createOptions(store)		  
	  info("Created simian options %s, going ahead with running process", simianOptions)
	  findDuplicates(simianOptions, files)
    } 
    
}

object SimianDuplicateTool{
  import au.com.redhillconsulting.simian.Option._
  lazy val preferenceKeyMap = Map(
		  (BALANCE_CURLY_BRACES    -> "simian.balance.curly.braces"),
		  (BALANCE_SQUARE_BRACKETS -> "simian.balance.square.brackets"),
		  (IGNORE_CHARACTER_CASE   -> "simian.ignore.character.case"),
		  (IGNORE_CHARACTERS       -> "simian.ignore.characters"),
		  (IGNORE_CURLY_BRACES     -> "simian.ignore.curly.braces"),
		  (IGNORE_IDENTIFIERS      -> "simian.ignore.identifiers"),
		  (IGNORE_IDENTIFIER_CASE  -> "simian.ignore.identifier.case"),
		  (IGNORE_MODIFIERS        -> "simian.ignore.modifiers"),
		  (IGNORE_NUMBERS          -> "simian.ignore.numbers")
  )
  
  def findDuplicates(simianOps: Options, fileLst: Array[String]) = new SimianRunner(simianOps, fileLst) run
  
 def createOptions(store: PreferenceStore) = {
	  val options = new Options
      preferenceKeyMap foreach ( keyValue => options setOption(keyValue._1, store(keyValue._2).toBoolean))
	  options setOption(Option.THRESHOLD, store("simian.threshold").toInt)
      options
  }
  
  class SimianRunner(val simianOptions: Options, val fileList: Array[String]) 
  	extends AuditListener{
    import scala.collection.mutable.{ArrayBuffer, HashSet}
  	private val duplicateSets = new ArrayBuffer[DuplicateSet]
    private val duplicateElements = new HashSet[DuplicateElement]
    private var duplicateSummary: DuplicateCheckSummary = _
    private var checkEnded = false
    private val checker = new Checker(this, simianOptions)
    private val fileLoader = new FileLoader(new StreamLoader(checker))
    
    def run = {
      fileList.foreach(fileLoader.load)
      if(checker.check)
        info("Duplicates detected in the current run!")
      else
        info("No duplicates detected in the current run!")
      this.checker.synchronized {
        while(!checkEnded)
        this.checker.wait(100)
      } 
      info("Finished running simian on the source files")
      (duplicateSummary, duplicateSets.toArray)
    }
    
    override def block(simianBlock: Block){
      val src = simianBlock.getSourceFile
      val duplicateElement = new DuplicateElement(simianBlock.getStartLineNumber,
        		simianBlock.getEndLineNumber, 
        		EnrichedSourceFile(src.getFilename, src.getFilename,
                             	   src.getRawLineCount,src.getSignificantLineCount) )
      debug("stored duplicate element: %s", duplicateElement)
      duplicateElements += duplicateElement
    }
    
    override def endCheck(cs: CheckSummary) {
    	this.duplicateSummary = DuplicateCheckSummary(cs.getDuplicateFileCount,
    			cs.getDuplicateLineCount, cs.getDuplicateLinePercentage, 
    			cs.getTotalFileCount, cs.getTotalRawLineCount,
    			cs.getTotalSignificantLineCount, cs.getProcessingTime)
      this.checker.synchronized {
        this.checkEnded = true
        this.checker.notifyAll
      }
    }
    
    override def endSet(arg: String){
    	duplicateSets += new DuplicateSet(this.lineCount, this.duplicateElements.toArray, "")
    	this.duplicateElements.clear
    }

    override def startCheck(x: Options){}
    
    override def fileProcessed(src: SimianSourceFile){
      debug("Simian finished processing file: %s", src.getFilename)
    }
    override def startSet(lineCnt: Int) = this.lineCount = lineCnt
    private var lineCount = 0
  }
}      
